package guitplugin;

import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.apt.Filer;
import com.sun.mirror.apt.Filer.Location;
import com.sun.mirror.apt.Messager;
import com.sun.mirror.declaration.AnnotationMirror;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.declaration.AnnotationTypeElementDeclaration;
import com.sun.mirror.declaration.AnnotationValue;
import com.sun.mirror.declaration.ClassDeclaration;
import com.sun.mirror.declaration.Declaration;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

public class I18nProcessor implements AnnotationProcessor {

  public static String newline = System.getProperty("line.separator");

  AnnotationProcessorEnvironment env;

  public I18nProcessor(AnnotationProcessorEnvironment env) {
    this.env = env;
    root = env.getOptions().get("-sourcepath").split("[:]");
  }

  private final String[] root;

  public AnnotationProcessorEnvironment getEnvironment() {
    return env;
  }

  @Override
  @SuppressWarnings("unchecked")
  public void process() {
    Filer filer = env.getFiler();
    Messager messager = env.getMessager();

    Collection<Declaration> annotatedTypes =
        env.getDeclarationsAnnotatedWith((AnnotationTypeDeclaration) env
            .getTypeDeclaration("com.guit.client.apt.GwtI18n"));
    for (Declaration decl : annotatedTypes) {
      if (decl instanceof ClassDeclaration) {
        ClassDeclaration classDeclaration = (ClassDeclaration) decl;

        Collection<AnnotationMirror> mirros = classDeclaration.getAnnotationMirrors();
        for (AnnotationMirror m : mirros) {
          if (m.getAnnotationType().getDeclaration().getQualifiedName().equals(
              "com.guit.client.apt.GwtI18n")) {
            try {
              Map<AnnotationTypeElementDeclaration, AnnotationValue> values = m.getElementValues();
              AnnotationValue v = values.values().iterator().next();

              String pkg = classDeclaration.getPackage().getQualifiedName();
              String packageLocation = pkg.replace(".", "/") + "/";

              // The first one is the default
              boolean isFirst = true;

              ArrayList<AnnotationValue> locales = (ArrayList<AnnotationValue>) v.getValue();
              for (AnnotationValue locale : locales) {
                String file =
                    classDeclaration.getSimpleName() + (isFirst ? "" : "_" + locale.getValue())
                        + ".properties";
                String target =
                    classDeclaration.getSimpleName().replaceAll("_", "")
                        + "GuitViewImplBinderImplGenMessages"
                        + (isFirst ? "" : "_" + locale.getValue()) + ".properties";
                isFirst = false;

                String contents = getFileContents(packageLocation + file);

                PrintWriter writer =
                    filer.createTextFile(Location.SOURCE_TREE, pkg, new File(target), "UTF-8");
                writer.println(contents);
                writer.close();
              }
            } catch (Exception e) {
              messager.printError(classDeclaration.getPosition(), e.toString());
            }

            break;
          }
        }
      }
    }
  }

  private String getFileContents(String file) {
    try {
      StringBuilder sb = new StringBuilder();
      FileInputStream fis = null;
      for (int n = 0; n < root.length && fis == null; n++) {
        String r = root[n];
        try {
          fis = new FileInputStream(r + "/" + file);
          DataInputStream in = new DataInputStream(fis);
          InputStreamReader isr = new InputStreamReader(in);
          BufferedReader br = new BufferedReader(isr);
          String strLine;
          while ((strLine = br.readLine()) != null) {
            sb.append(strLine);
            sb.append(newline);
          }
          br.close();
          isr.close();
          in.close();
        } catch (Exception e) {
          continue;
        }
      }
      if (fis == null) {
        throw new RuntimeException("The file " + file + " was not found.");
      }

      return sb.toString();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
}
